﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
using NavigationPane.Properties;
using System.Windows.Interop;
using System.Collections.ObjectModel;
using System.Windows.Data;
using Stema.Controls.Utils;

namespace Stema.Controls
{
 /// <summary>

 /// </summary>
 [
  TemplatePart(Name = NavigationPaneExpanderParts.PART_ContentHost, Type = typeof(ItemsPresenter)),
  TemplatePart(Name = NavigationPaneExpanderParts.PART_ContentHostContainerUnexpanded, Type = typeof(Border)),
  TemplatePart(Name = NavigationPaneExpanderParts.PART_ContentHostContainerExpanded, Type = typeof(Border)),

  TemplatePart(Name = NavigationPaneExpanderParts.PART_HeaderHost, Type = typeof(Border)),
  TemplatePart(Name = NavigationPaneExpanderParts.PART_HeaderHostMinimized, Type = typeof(Border)),

  TemplatePart(Name = NavigationPaneExpanderParts.PART_Popup, Type = typeof(Popup)),
  TemplatePart(Name = NavigationPaneExpanderParts.PART_CloseButton, Type = typeof(ToggleButton)),

  TemplatePart(Name = NavigationPaneExpanderParts.PART_ResizeThumb, Type = typeof(Thumb)),
  TemplatePart(Name = NavigationPaneExpanderParts.PART_MininizedSizeProvider, Type = typeof(FrameworkElement)),

  StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(NavigationPaneItem))
 ]
 public class NavigationPaneExpander : HeaderedItemsControl, IMinimizeHelped
 {
  internal static class NavigationPaneExpanderParts
  {
   public const string PART_ContentHost = "PART_ContentHost";
   public const string PART_ContentHostContainerUnexpanded = "PART_ContentHostContainerUnexpanded";
   public const string PART_ContentHostContainerExpanded = "PART_ContentHostContainerExpanded";

   public const string PART_HeaderHost = "PART_HeaderHost";
   public const string PART_HeaderHostMinimized = "PART_HeaderHostMinimized";

   public const string PART_Popup = "PART_Popup";
   public const string PART_CloseButton = "PART_CloseButton";

   public const string PART_ResizeThumb = "PART_ResizeThumb";
   public const string PART_MininizedSizeProvider = "PART_MininizedSizeProvider";
  }

  static NavigationPaneExpander()
  {
   DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigationPaneExpander), new FrameworkPropertyMetadata(typeof(NavigationPaneExpander)));

   EventManager.RegisterClassHandler(typeof(Window), Mouse.PreviewMouseDownEvent, new MouseButtonEventHandler(OnPreviewMouseButtonDown), true);
   EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseButtonDown), true);
   EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseUpEvent, new MouseButtonEventHandler(OnMouseButtonUp), true);
   EventManager.RegisterClassHandler(typeof(Window), Mouse.MouseMoveEvent, new MouseEventHandler(OnMouseMove), true);
  }

  protected override DependencyObject GetContainerForItemOverride()
  {
   return new NavigationPaneItem();
  }

  protected override bool IsItemItsOwnContainerOverride(object item)
  {
   return item is NavigationPaneItem;
  }

  #region TEMPLATED PARTS

  internal ItemsPresenter part_contentHost;
  private Border part_contentHostContainerExpanded;
  private Border part_contentHostContainerUnexpanded;

  private Border part_headerHost;
  private Border part_headerHostMinimized;

  private Popup part_popup;
  private ToggleButton part_closeButton;

  private MinimizeHelper minimizeHelper;
  MinimizeHelper IMinimizeHelped.ResizeHelper
  {
   get { return minimizeHelper; }
  }

  public event RoutedEventHandler MinimizedChanged
  {
   add { AddHandler(MinimizedChangedEvent, value); }
   remove { RemoveHandler(MinimizedChangedEvent, value); }
  }
  public static readonly RoutedEvent MinimizedChangedEvent = EventManager.RegisterRoutedEvent(
      "MinimizedChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NavigationPaneExpander));

  private void RaiseMinimizedChangedEvent()
  {
   RoutedEventArgs newEventArgs = new RoutedEventArgs(MinimizedChangedEvent);
   RaiseEvent(newEventArgs);
  }

  void IMinimizeHelped.OnIsMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
   CoerceValue(IsPopupOpenProperty);

   SwitchHeader((bool)e.NewValue);
   SwitchContentToPopUp((bool)e.NewValue);
   RaiseMinimizedChangedEvent();
  }

  public override void OnApplyTemplate()
  {
   base.OnApplyTemplate();

   part_contentHost = GetTemplateChild(NavigationPaneExpanderParts.PART_ContentHost) as ItemsPresenter;
   part_contentHostContainerExpanded = GetTemplateChild(NavigationPaneExpanderParts.PART_ContentHostContainerExpanded) as Border;
   part_contentHostContainerUnexpanded = GetTemplateChild(NavigationPaneExpanderParts.PART_ContentHostContainerUnexpanded) as Border;

   part_headerHost = GetTemplateChild(NavigationPaneExpanderParts.PART_HeaderHost) as Border;
   part_headerHostMinimized = GetTemplateChild(NavigationPaneExpanderParts.PART_HeaderHostMinimized) as Border;

   part_closeButton = GetTemplateChild(NavigationPaneExpanderParts.PART_CloseButton) as ToggleButton;
   if(part_closeButton != null)
    part_closeButton.Click += new RoutedEventHandler(part_closeButton_Click);

   InitPopup();

   // check minimizeHelper because on blend when you try to edit the style BeginInit() is not already called
   // or is not called at all !! ?? Anyways... check to avoid use of null value reference
   if (minimizeHelper != null)
    minimizeHelper.Init(GetTemplateChild(NavigationPaneExpanderParts.PART_ResizeThumb) as Thumb,
     GetTemplateChild(NavigationPaneExpanderParts.PART_MininizedSizeProvider) as FrameworkElement, part_contentHost);
  }

  internal FrameworkElement Get_PART_ContentHost()
  {
   return part_contentHost;
  }

  public override void BeginInit()
  {
   base.BeginInit();
   minimizeHelper = new MinimizeHelper(this);
  }

  #endregion

  #region  EXPAND HANDLING

  public object ExpandToolTip
  {
   get { return (object)GetValue(ExpandToolTipProperty); }
   set { SetValue(ExpandToolTipProperty, value); }
  }
  public static readonly DependencyProperty ExpandToolTipProperty =
      DependencyProperty.Register("ExpandToolTip", typeof(object), typeof(NavigationPaneExpander),
      new UIPropertyMetadata(NPR.NavigationPaneExpander_ExpandToolTip, MinimizeHelper.ButtonToolTipChanged));

  public object MinimizeToolTip
  {
   get { return (object)GetValue(MinimizeToolTipProperty); }
   set { SetValue(MinimizeToolTipProperty, value); }
  }
  public static readonly DependencyProperty MinimizeToolTipProperty =
      DependencyProperty.Register("MinimizeToolTip", typeof(object), typeof(NavigationPaneExpander),
      new UIPropertyMetadata(NPR.NavigationPaneExpander_MinimizeToolTip, MinimizeHelper.ButtonToolTipChanged));

  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public object ButtonToolTip
  {
   get { return (object)GetValue(ButtonToolTipProperty); }
  }
  internal static readonly DependencyPropertyKey ButtonToolTipPropertyKey =
      DependencyProperty.RegisterReadOnly("ButtonToolTip", typeof(object), typeof(NavigationPaneExpander),
      new UIPropertyMetadata(NPR.NavigationPaneExpander_MinimizeToolTip, null, MinimizeHelper.CoerceButtonToolTip));
  public static readonly DependencyProperty ButtonToolTipProperty = ButtonToolTipPropertyKey.DependencyProperty;

  public bool IsMinimized
  {
   get { return (bool)GetValue(IsMinimizedProperty); }
   set { SetValue(IsMinimizedProperty, value); }
  }
  public static readonly DependencyProperty IsMinimizedProperty =
      DependencyProperty.Register("IsMinimized", typeof(bool), typeof(NavigationPaneExpander),
      new FrameworkPropertyMetadata(false,
       FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
       new PropertyChangedCallback(MinimizeHelper.OnIsMinimizedChanged), new CoerceValueCallback(MinimizeHelper.CoerceIsMinimized)));

  private delegate void SetMinimized(NavigationPaneExpander expander, bool minimized);

  private void SwitchContentToPopUp(bool minimized)
  {
   //Application.Current.Dispatcher.BeginInvoke((SetMinimized)((e, m) =>
   //{
   NavigationPaneExpander e = this;
   bool m = minimized;

   Border expanded = e.part_contentHostContainerExpanded;
   Border unexpanded = e.part_contentHostContainerUnexpanded;
   ItemsPresenter presenter = e.part_contentHost;
   if (expanded != null && unexpanded != null && presenter != null)
   {
    if (m)
    {
     expanded.Child = null;
     unexpanded.Child = presenter;
     //unexpanded.InvalidateVisual();
    }
    else
    {
     unexpanded.Child = null;
     expanded.Child = presenter;
    }
   }
   //}), DispatcherPriority.Render, this, minimized);
  }

  private void SwitchHeader(bool isMinimized)
  {
   if (part_headerHost != null && part_headerHostMinimized != null)
   {
    if (isMinimized)
    {
     UIElement o = part_headerHost.Child;
     part_headerHost.Child = null;
     part_headerHostMinimized.Child = o;
    }
    else
    {
     UIElement o = part_headerHostMinimized.Child;
     part_headerHostMinimized.Child = null;
     part_headerHost.Child = o;
    }
   }
  }

  private double MinimizedMinWidth
  {
   get { return (double)GetValue(MinimizedMinWidthProperty); }
   set { SetValue(MinimizedMinWidthProperty, value); }
  }
  internal static readonly DependencyProperty MinimizedMinWidthProperty =
      DependencyProperty.Register("MinimizedMinWidth", typeof(double), typeof(NavigationPaneExpander),
      new PropertyMetadata(0.0, null, new CoerceValueCallback(MinimizeHelper.CoerceMinimizedMinWidth)));

  public bool HasResizeThumb
  {
   get { return (bool)GetValue(HasResizeThumbProperty); }
   set { SetValue(HasResizeThumbProperty, value); }
  }
  public static readonly DependencyProperty HasResizeThumbProperty =
      DependencyProperty.Register("HasResizeThumb", typeof(bool), typeof(NavigationPaneExpander), new UIPropertyMetadata(true));

  #endregion

  #region POPUP HANDLING

  private class PopupData
  {
   internal Cursor Cursor;
   internal Popup Popup;
   internal FrameworkElement ControlledElement;
   internal bool IsResizing;
   internal PopupAdorner Adorner;
   internal PopupAdorner ChildAdorner;
   internal Style PopupResizePreviewStyle;

   internal PopupData(Popup popup, FrameworkElement controlledElement, Style previewStyle)
   {
    this.ControlledElement = controlledElement;
    this.Popup = popup;
    this.PopupResizePreviewStyle = previewStyle;
    IsResizing = false;
    Adorner = null;
    this.Cursor = (popup.Child as FrameworkElement).Cursor;
   }

   internal void EndResize()
   {
    if (Adorner != null)
     (VisualTreeHelper.GetParent(Adorner) as AdornerLayer).Remove(Adorner);
    if (ChildAdorner != null)
     (VisualTreeHelper.GetParent(ChildAdorner) as AdornerLayer).Remove(ChildAdorner);

    ControlledElement.Width = ControlledElement.ActualWidth + ChildAdorner.EffectiveOffset;

    FrameworkElement element = Popup.Child as FrameworkElement;
    element.Cursor = Cursor;
    (window).Cursor = null;

    IsResizing = false;
   }

   private Window window;
   internal void StartResize(Window sender)
   {
    window = sender;
    // damn!!!! 
    // I'm forced to use two separated adorners
    // to have it displayed over the popup child
    // and to have it also outside of the child contorl
    // if you know a better way to do this
    // please post a discussion on navigationpane.codeplex.com

    AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(Popup);
    if (adornerLayer != null)
    {
     Adorner = new PopupAdorner(Popup, Popup.Placement, PopupResizePreviewStyle);
     adornerLayer.Add(Adorner);
    }

    adornerLayer = AdornerLayer.GetAdornerLayer(Popup.Child);
    if (adornerLayer != null)
    {
     ChildAdorner = new PopupAdorner(Popup.Child, Popup.Placement, PopupResizePreviewStyle);
     adornerLayer.Add(ChildAdorner);
    }

    FrameworkElement child = Popup.Child as FrameworkElement;

    (sender as Window).Cursor = System.Windows.Input.Cursors.SizeWE;
    child.Cursor = System.Windows.Input.Cursors.SizeWE;

    IsResizing = true;
   }
  }

  private static class PopupHelper
  {
   private static Dictionary<Window, PopupData> _container;

   internal static void RegisterAsOpened(Popup popup, FrameworkElement controlledElement, Style previewStyle)
   {
    if (popup == null)
     return;

    Window window = Window.GetWindow(popup);
    if (_container == null)
     _container = new Dictionary<Window, PopupData>();
    if (!_container.ContainsKey(window))
     _container.Add(window, new PopupData(popup, controlledElement, previewStyle));
   }

   internal static void UnRegisterAsOpened(Popup popup)
   {
    if (popup == null)
     return;

    Window window = Window.GetWindow(popup);
    if (_container.ContainsKey(window))
     _container.Remove(window);
    if (_container.Count == 0)
     _container = null;
   }

   internal static PopupData GetPopupData(Window window)
   {
    if (window != null && _container != null && _container.ContainsKey(window))
     return _container[window];
    return null;
   }
  }

  private class PopupAdorner : Adorner
  {
   private Decorator _decorator;
   private TranslateTransform Translation;
   private PlacementMode PlacementMode;

   internal PopupAdorner(UIElement element, PlacementMode placementMode, Style previewStyle)
    : base(element)
   {
    PlacementMode = placementMode;

    Control control = new Control();
    control.SnapsToDevicePixels = true;
    control.Style = previewStyle;
    control.IsEnabled = false;
    Translation = new TranslateTransform();
    _decorator = new Decorator();
    _decorator.Child = control;
    _decorator.RenderTransform = Translation;
    AddVisualChild(_decorator);
   }

   protected override Size MeasureOverride(Size constraint)
   {
    Size s = Size.Empty;
    FrameworkElement element = null;
    Popup p = AdornedElement as Popup;
    if (p != null)
    {
     element = p.Child as FrameworkElement;
     s = element.RenderSize;
     s.Width = 1;
     //s.Height -= element.Margin.Top + element.Margin.Bottom;
    }
    else
    {
     s = base.MeasureOverride(constraint);
     if (PlacementMode == PlacementMode.Left && Offset > 0)
      s.Width -= (AdornedElement as FrameworkElement).Margin.Right;
    }

    double offset = Offset;
    if (PlacementMode == PlacementMode.Right)
     offset *= -1;

    if (element != null && (PlacementMode == PlacementMode.Right) && Offset > element.DesiredSize.Width - (element.Margin.Left + element.Margin.Right))
     s.Width = 0;
    if (s.Width + offset > 0)
     s.Width += offset;

    return s;
   }

   protected override Size ArrangeOverride(Size finalSize)
   {
    Popup p = AdornedElement as Popup;
    if (p != null)
    {
     FrameworkElement element = p.Child as FrameworkElement;
     Point loc = element.TranslatePoint(new Point(), p);
     loc.Y += element.Margin.Top;
     if (PlacementMode == PlacementMode.Left)
      loc.X += element.ActualWidth - element.Margin.Right;
     _decorator.Arrange(new Rect(loc, finalSize));
    }
    else
     _decorator.Arrange(new Rect(new Point(), finalSize));
    return finalSize;
   }

   protected override Visual GetVisualChild(int index)
   {
    if (index != 0)
     throw new ArgumentOutOfRangeException("index");
    return this._decorator;
   }

   private double offset;
   public double Offset
   {
    get { return offset; }
    set
    {
     offset = value;
     if (PlacementMode == PlacementMode.Right)
      Translation.X = offset;
     InvalidateMeasure();
    }
   }

   public double EffectiveOffset
   {
    get
    {
     if (PlacementMode == PlacementMode.Right)
      return offset * -1;
     return offset;
    }
   }

   protected override int VisualChildrenCount
   {
    get { return 1; }
   }
  }

  private void InitPopup()
  {
   part_popup = GetTemplateChild(NavigationPaneExpanderParts.PART_Popup) as Popup;
   if (part_popup != null)
   {
    Window w = Window.GetWindow(this);
    if (w != null)
    {
     w.SourceInitialized += new EventHandler(w_SourceInitialized);
     w.Deactivated += new EventHandler(window_Deactivated);
    }
    part_popup.Closed += new EventHandler(OnPopupClosed);
   }
  }

  void w_SourceInitialized(object sender, EventArgs e)
  {
   HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(sender as Window).Handle);
   source.AddHook(new HwndSourceHook(WndProc));
  }

  private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
  {
   if (msg == 0x00A1 && IsPopupOpen)
   {
    Close();
    handled = true;
   }
   else
    handled = false;
   return IntPtr.Zero;
  }

  private void window_Deactivated(object sender, EventArgs e)
  {
   if (IsPopupOpen)
    Close();
  }

  public bool IsPopupOpen
  {
   get { return (bool)GetValue(IsPopupOpenProperty); }
   set { SetValue(IsPopupOpenProperty, value); }
  }
  public static readonly DependencyProperty IsPopupOpenProperty =
      DependencyProperty.Register("IsPopupOpen", typeof(bool), typeof(NavigationPaneExpander),
      new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsPopupOpenChanged, new CoerceValueCallback(CoerceIsPopupOpen)));

  private static object CoerceIsPopupOpen(DependencyObject d, object value)
  {
   NavigationPaneExpander p = d as NavigationPaneExpander;
   return p.IsMinimized ? value : false;
  }

  private static void IsPopupOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
   NavigationPaneExpander expander = (NavigationPaneExpander)d;
   bool newValue = (bool)e.NewValue;
   bool oldValue = !newValue;

   // todo: implement automation
   //ComboBoxAutomationPeer peer = UIElementAutomationPeer.FromElement(element) as ComboBoxAutomationPeer;
   //if (peer != null)
   //{
   // peer.RaiseExpandCollapseAutomationEvent(oldValue, newValue);
   //}

   if (newValue)
   {
    if (expander.part_popup != null)
     PopupHelper.RegisterAsOpened(expander.part_popup, expander.part_contentHost, expander.PopupResizePreviewStyle);
    expander.OnPopupOpened();
   }
   else
   {
    expander.OnPopupClosed();
    PopupHelper.UnRegisterAsOpened(expander.part_popup);
   }
  }

  #region EVENTS

  public event RoutedEventHandler PopupOpened
  {
   add { AddHandler(PopupOpenedEvent, value); }
   remove { RemoveHandler(PopupOpenedEvent, value); }
  }
  public static readonly RoutedEvent PopupOpenedEvent = EventManager.RegisterRoutedEvent(
      "PopupOpened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NavigationPaneExpander));

  protected virtual void OnPopupOpened()
  {
   RoutedEventArgs newEventArgs = new RoutedEventArgs(PopupOpenedEvent);
   RaiseEvent(newEventArgs);
  }

  public event RoutedEventHandler PopupClosed
  {
   add { AddHandler(PopupClosedEvent, value); }
   remove { RemoveHandler(PopupClosedEvent, value); }
  }
  public static readonly RoutedEvent PopupClosedEvent = EventManager.RegisterRoutedEvent(
      "PopupClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NavigationPaneExpander));

  protected virtual void OnPopupClosed()
  {
   RoutedEventArgs newEventArgs = new RoutedEventArgs(PopupClosedEvent);
   RaiseEvent(newEventArgs);
  }

  private void OnPopupClosed(object source, EventArgs e)
  {
   OnPopupClosed();
  }

  #endregion

  private bool HasCapture
  {
   get { return (Mouse.Captured == this); }
  }

  private void Close()
  {
   if (IsPopupOpen)
   {
    PopupData data = PopupHelper.GetPopupData(Window.GetWindow(this));
    if (data != null && data.IsResizing)
     data.EndResize();
    SetCurrentValue(IsPopupOpenProperty, false);
   }
  }

  private static bool CheckClose(Popup popup, DependencyObject element)
  {
   if (popup != null && popup.Child != null)
   {
    object o = popup.Child.FindCommonVisualAncestor(element);
    return popup.FindCommonVisualAncestor(element) != null;
   }
   return false;
  }

  private static bool CheckResizeZone(Popup popup)
  {
   if (popup.Child != null)
   {
    FrameworkElement element = popup.Child as FrameworkElement;
    Point p = Mouse.GetPosition(element);
    if (element != null)
    {
     double delta = 5;
     double x = popup.Placement == PlacementMode.Left ? (p.X - element.ActualWidth) + delta : p.X;
     return x > -1 && x < delta;
    }
   }
   return false;
  }

  public static void OnMouseMove(object sender, MouseEventArgs e)
  {
   PopupData popupData = PopupHelper.GetPopupData(sender as Window);
   if (popupData == null)
    return;
   if (popupData.IsResizing)
   {
    FrameworkElement child = popupData.Popup.Child as FrameworkElement;
    Point p = e.MouseDevice.GetPosition(child);
    double offset = p.X;
    if (popupData.Popup.Placement == PlacementMode.Left)
     offset -= child.ActualWidth;

    popupData.Adorner.Offset = offset;
    popupData.ChildAdorner.Offset = offset;
   }
   else
   {
    FrameworkElement element = popupData.Popup.Child as FrameworkElement;
    if (element != null)
    {
     if (CheckResizeZone(popupData.Popup))
     {
      if (element.Cursor != System.Windows.Input.Cursors.SizeWE)
       element.Cursor = System.Windows.Input.Cursors.SizeWE;
     }
     else if (element.Cursor != popupData.Cursor)
      element.Cursor = popupData.Cursor;
    }
   }
  }

  public static void OnMouseButtonUp(object sender, MouseButtonEventArgs e)
  {
   if (e.LeftButton == MouseButtonState.Released)
   {
    PopupData popupData = PopupHelper.GetPopupData(sender as Window);
    if (popupData != null && popupData.IsResizing)
    {
     popupData.EndResize();
     e.Handled = true;
    }
   }
  }

  public static void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
  {
   if (e.LeftButton == MouseButtonState.Pressed)
   {
    PopupData popupData = PopupHelper.GetPopupData(sender as Window);
    if (popupData != null && popupData.ControlledElement != null && popupData.Popup.Child != null && !popupData.IsResizing)
    {
     if (CheckResizeZone(popupData.Popup))
     {
      popupData.StartResize(sender as Window);
      e.Handled = true;
     }
    }
   }
  }

  public Style PopupResizePreviewStyle
  {
   get { return (Style)GetValue(PopupResizePreviewStyleProperty); }
   set { SetValue(PopupResizePreviewStyleProperty, value); }
  }
  public static readonly DependencyProperty PopupResizePreviewStyleProperty =
      DependencyProperty.Register("PopupResizePreviewStyle", typeof(Style), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));

  public static void OnPreviewMouseButtonDown(object sender, MouseButtonEventArgs e)
  {
   PopupData popupData = PopupHelper.GetPopupData(sender as Window);
   if (popupData == null)
    return;
   if (CheckClose(popupData.Popup, (DependencyObject)e.OriginalSource))
   {
    popupData.Popup.IsOpen = false;
    e.Handled = true;
   }
  }

  #endregion

  public static bool GetCanResize(DependencyObject obj)
  {
   return (bool)obj.GetValue(CanResizeProperty);
  }
  public static void SetCanResize(DependencyObject obj, bool value)
  {
   obj.SetValue(CanResizeProperty, value);
  }
  public static readonly DependencyProperty CanResizeProperty =
      DependencyProperty.RegisterAttached("CanResize", typeof(bool), typeof(NavigationPaneExpander), new UIPropertyMetadata(true));

  public Dock Orientation
  {
   get { return (Dock)GetValue(OrientationProperty); }
   set { SetValue(OrientationProperty, value); }
  }
  public static readonly DependencyProperty OrientationProperty =
      DependencyProperty.Register("Orientation", typeof(Dock), typeof(NavigationPaneExpander), new UIPropertyMetadata(Dock.Left));

  public object BarToolTip
  {
   get { return (object)GetValue(BarToolTipProperty); }
   set { SetValue(BarToolTipProperty, value); }
  }
  public static readonly DependencyProperty BarToolTipProperty =
      DependencyProperty.Register("BarToolTip", typeof(object), typeof(NavigationPaneExpander), new UIPropertyMetadata(NPR.NavigationPaneExpander_BarToolTip));

  public bool IsHeaderVisible
  {
   get { return (bool)GetValue(IsHeaderVisibleProperty); }
   set { SetValue(IsHeaderVisibleProperty, value); }
  }
  public static readonly DependencyProperty IsHeaderVisibleProperty =
      DependencyProperty.Register("IsHeaderVisible", typeof(bool), typeof(NavigationPaneExpander), new UIPropertyMetadata(false));

  public bool IsCloseButtonVisible
  {
   get { return (bool)GetValue(IsCloseButtonVisibleProperty); }
   set { SetValue(IsCloseButtonVisibleProperty, value); }
  }
  public static readonly DependencyProperty IsCloseButtonVisibleProperty =
      DependencyProperty.Register("IsCloseButtonVisible", typeof(bool), typeof(NavigationPaneExpander), new UIPropertyMetadata(false));

  void part_closeButton_Click(object sender, RoutedEventArgs e)
  {
   ((ToggleButton)sender).IsChecked = false;
   RaiseEvent(new RoutedEventArgs(CloseButtonClickEvent));
  }

  public ICommand CloseCommand
  {
   get { return (ICommand)GetValue(CloseCommandProperty); }
   set { SetValue(CloseCommandProperty, value); }
  }
  public static readonly DependencyProperty CloseCommandProperty =
      DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));

  public object CloseCommandParameter
  {
   get { return (object)GetValue(CloseCommandParameterProperty); }
   set { SetValue(CloseCommandParameterProperty, value); }
  }
  public static readonly DependencyProperty CloseCommandParameterProperty =
      DependencyProperty.Register("CloseCommandParameter", typeof(object), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));

  public IInputElement CloseCommandTarget
  {
   get { return (IInputElement)GetValue(CloseCommandTargetProperty); }
   set { SetValue(CloseCommandTargetProperty, value); }
  }
  public static readonly DependencyProperty CloseCommandTargetProperty =
      DependencyProperty.Register("CloseCommandTarget", typeof(IInputElement), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));

  public event RoutedEventHandler CloseButtonClick
  {
   add { AddHandler(CloseButtonClickEvent, value); }
   remove { RemoveHandler(CloseButtonClickEvent, value); }
  }
  public static readonly RoutedEvent CloseButtonClickEvent = EventManager.RegisterRoutedEvent(
      "CloseButtonClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NavigationPaneExpander));

  /// <summary>
  /// True if we are inside a NavigationPane
  /// </summary>
  public bool IsInsideNavigationPane
  {
   get { return (bool)GetValue(IsInsideNavigationPaneProperty); }
   protected set { SetValue(IsInsideNavigationPanePropertyKey, value); }
  }
  private static readonly DependencyPropertyKey IsInsideNavigationPanePropertyKey =
      DependencyProperty.RegisterReadOnly("IsInsideNavigationPane", typeof(bool), typeof(NavigationPaneExpander),
      new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
  public static readonly DependencyProperty IsInsideNavigationPaneProperty = IsInsideNavigationPanePropertyKey.DependencyProperty;

  protected override void OnVisualParentChanged(DependencyObject oldParent)
  {
   base.OnVisualParentChanged(oldParent);
   IsInsideNavigationPane = TemplatedParent is NavigationPane;
  }

  protected override void ClearContainerForItemOverride(DependencyObject element, object item)
  {
   base.ClearContainerForItemOverride(element, item);
   if (item is HeaderedContentControl)
   {
    // restores the item header removed by NavigationPaneExpanderItemsHeader.FromHeaderedContentControl
    // in PrepareContainerForItemOverride
    (item as HeaderedContentControl).Header = (element as NavigationPaneItem).Header;
   }
  }

  protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
  {
   if (item is HeaderedContentControl)
   {
    if (itemsHeaders == null)
    {
     itemsHeaders = new ObservableCollection<NavigationPaneExpanderItemsHeader>();
     ItemsHeaders = new ReadOnlyObservableCollection<NavigationPaneExpanderItemsHeader>(itemsHeaders);
    }

    //FromHeaderedContentControl(item) removes the header form the item setting it to null
    //this is restored in ClearContainerForItemOverride
    NavigationPaneExpanderItemsHeader o = NavigationPaneExpanderItemsHeader.FromHeaderedContentControl(item);
    if (o != null)
     itemsHeaders.Add(o);
   }
   base.PrepareContainerForItemOverride(element, item);

   Binding b = new Binding();
   b.Source = item;
   b.Path = new PropertyPath(CanResizeProperty);
   (element as FrameworkElement).SetBinding(CanResizeProperty, b);
  }

  private ObservableCollection<NavigationPaneExpanderItemsHeader> itemsHeaders;
  public ReadOnlyObservableCollection<NavigationPaneExpanderItemsHeader> ItemsHeaders
  {
   get { return (ReadOnlyObservableCollection<NavigationPaneExpanderItemsHeader>)GetValue(ItemsHeadersProperty); }
   set { SetValue(ItemsHeadersProperty, value); }
  }
  public static readonly DependencyProperty ItemsHeadersProperty =
      DependencyProperty.Register("ItemsHeaders", typeof(ReadOnlyObservableCollection<NavigationPaneExpanderItemsHeader>), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));

  public DataTemplate ItemsHeadersTemplate
  {
   get { return (DataTemplate)GetValue(ItemsHeadersTemplateProperty); }
   set { SetValue(ItemsHeadersTemplateProperty, value); }
  }
  public static readonly DependencyProperty ItemsHeadersTemplateProperty =
      DependencyProperty.Register("ItemsHeadersTemplate", typeof(DataTemplate), typeof(NavigationPaneExpander), new UIPropertyMetadata(null));
 }

 public class NavigationPaneExpanderItemsHeader
 {
  public ImageSource Image { get; private set; }
  public object Content { get; private set; }

  private NavigationPaneExpanderItemsHeader() { }
  internal static NavigationPaneExpanderItemsHeader FromHeaderedContentControl(object control)
  {
   if (control is HeaderedContentControl)
   {
    NavigationPaneExpanderItemsHeader item = new NavigationPaneExpanderItemsHeader();
    if (control is NavigationPaneItem)
     item.Image = (control as NavigationPaneItem).ImageSmall;
    item.Content = (control as HeaderedContentControl).Header;
    (control as HeaderedContentControl).Header = null;
    return item;
   }
   return null;
  }
 }
}
